#include "TypeEntryFrameItem.h"
#include "QPainter"
#include "TypeEntryItem.h"
#include "TypeDialog.h"
#include "TypeUnfoldArrayButton.h"
#include "WOPM.h"
#include "DiagramScene.h"
#include "TypeManager.h"
#include "AbstractManager.h"
#include "TypeVariableEntry.h"
#include "Factory_xNodeType.h"
#include "xMappingNode.h"
#include "AbstractPanel.h"
#include "TypeVariablePanel.h"
#include "GraphicsText.h"
#include "NodeOutPort.h"

#include <cassert>

TypeEntryFrameItem::TypeEntryFrameItem( WOP_Entry* entry, std::vector<xMappingNode*> &entryList, DiagramScene* scene, AbstractPanel* panel)
	:PanelItem( entry->getName(), scene->getManager(), panel)
{
	this->_scene = scene;
	this->_wopEntry = entry;
	this->_mpnNode = NULL;
	this->_nodeType = AbstractShapeItem::ENTRY_NODE_FRAME;
	this->_isExpanded = true;

	panel->insertItem(this);

	this->createEntryNodes(entryList);
	// 如果type是array，則會多一個將array展開或是摺疊的按鈕
	if ( _wopEntry->getTypeStr() == "array") {
		_changeTypeButton = new TypeUnfoldArrayButton(this);
		this->setExpanded(false);
	}
	_graphicsTextName->setAlignment(Qt::AlignLeft);
	_graphicsTextName->setX( 33 );
}

TypeEntryFrameItem::~TypeEntryFrameItem(void)
{
	
}

void TypeEntryFrameItem::paint( QPainter* painter, const QStyleOptionGraphicsItem* option, QWidget* widget )
{
	// 畫出frame header的底色
	painter->setPen(QPen(Qt::NoPen));
	painter->setBrush(QBrush(QColor("#CACACA")));
	painter->drawRect( 0, 0, this->_width, HEIGHT );

	QImage icon;
	if ( _isExpanded){
		icon = QImage("./images/folder_open.png");
	} else {
		icon = QImage("./images/folder.png");
	}
	painter->drawImage(18,7,icon);
	

	// 畫分隔線
	painter->setPen(QPen(QColor("#AAAAAA")));
	painter->drawLine( 0, HEIGHT, this->_width, HEIGHT);
}

QRectF TypeEntryFrameItem::boundingRect() const
{
	return QRectF( 0, 0, this->_width, HEIGHT );
}

void TypeEntryFrameItem::setExpanded( bool expand )
{
	this->_isExpanded = expand;

	// 顯示或隱藏 foreach area
	QPoint pos;
	if ( expand ){
		pos.setX(-100000);
		pos.setY(-100000);
	} else {
		pos.setX(0);
		pos.setY(0);
	}
	TypeDialog *dialog = dynamic_cast<TypeDialog*>(_manager->getMappingDialog());
	assert(dialog);
	dialog->getForeachRect()->setPos(pos);
	unfoldArray(_isExpanded);
}

bool TypeEntryFrameItem::getExpanded()
{
	return this->_isExpanded;
}

void TypeEntryFrameItem::setupPort()
{

}

void TypeEntryFrameItem::createEntryNodes( std::vector<xMappingNode*>& entryList )
{
	using namespace std;
	TypeManager* manager= dynamic_cast<TypeManager*>(_manager);
	assert(manager);

	// 如果type是array的話，先建立一個Generic的entry來代表這個array，並且先將它隱藏起來
	if ( _wopEntry->getTypeStr() == "array") {
		int dimension = dynamic_cast<WOP_Array_Entry*>(_wopEntry)->getDimension();		// 取得array的維度

		// generic entry的名稱會長得像 array_name[i][j].. 這樣
		// 所以取得維度後用 for loop 來建構generic entry名稱，每當i增加1，[]裡面的Ascii也加一
		string name = _name;
		QChar index('i'); 
		for ( int i = 0; i < dimension; ++ i)
		{
			name = name +"[" + QString(QChar(index.toAscii()+i)).toStdString() + "]";
		}

		// 建立 generic entry
		xNodeType* nodeType = Factory_xNodeType::create_xnodetype("wop",_wopEntry);
		nodeType->setName(name);

		xMappingTree *xmt = _scene->getManager()->getMappingTree();
		xMappingNode *genericNode = xmt->create_node(nodeType);
		xmt->add_input_terminal(genericNode);

		TypeEntryItem* genericEntry = manager->createEntryItem( name, "ref", genericNode, _wopEntry);
		manager->getVariablePanel()->insertItem(genericEntry,0);
		genericEntry->setVisible(false);
		genericEntry->setZValue(-1);
		_entryNodes.push_back(genericEntry);
	}

	vector<WOP_Entry*> wopList = manager->getEntry()->getWopList();

	for ( int i = 0; i < entryList.size(); ++i )
	{
		TypeEntryItem* entry = manager->createEntryItem( manager->getEntry()->getEntryNameAT(i), manager->getEntry()->getEntryTypeAT(i), entryList.at(i), wopList.at(i));
		manager->getVariablePanel()->insertItem(entry,i+1);
		_entryNodes.push_back(entry);
	}

}

void TypeEntryFrameItem::unfoldArray(bool unfold)
{
	int count = 0;
	_entryNodes.at(0)->setVisible(!unfold);

	for ( int i = 1; i < _entryNodes.size(); ++i )
	{
		_entryNodes.at(i)->setVisible(unfold);
		_entryNodes.at(i)->setForeachElements(!unfold);
		if ( unfold ){
			count++;
		}
	}

	std::vector<AbstractShapeItem*>::iterator itr;
	for ( itr = _manager->getNodeList().begin(); itr != _manager->getNodeList().end(); ++itr )
	{
		if ( !unfold ){
			if (_manager->isInForEachRect(*itr)){
				(*itr)->getMappingNode()->setForeachElements(true);
			} else {
				(*itr)->getMappingNode()->setForeachElements(false);
			}
		} else {
			(*itr)->getMappingNode()->setForeachElements(false);
		}

	}

	// 當 frame 被 unfold 時，要把 entry 上的 links 清除
	if ( unfold ){
		_entryNodes.at(0)->removeAllLinks();
	} else {
		std::vector<TypeEntryItem*>::iterator itr;
		for ( itr = _entryNodes.begin()+1; itr != _entryNodes.end(); ++itr )
		{
			(*itr)->removeAllLinks();
		}
	}

	int height = ( count * HEIGHT );
	
	//假如展開的高度比 sceneRect 還大，則重設 sceneRect 高度
	//如果是把frame折疊起來而且sceneRect曾經變動過，就將sceneRect高度設回原本的高度
	if ( height > AbstractMappingWindow::SCENE_HEIGHT ){
		//_scene->sceneRect().setHeight(height +100);
		_scene->setSceneRect(0,0,_scene->width(),height +100);
	}
	if ( !unfold && 
		_scene->sceneRect().height() > AbstractMappingWindow::SCENE_HEIGHT){
		_scene->setSceneRect(0,0,_scene->width(),AbstractMappingWindow::SCENE_HEIGHT);
	}

	_scene->update();


}

void TypeEntryFrameItem::remove()
{
	assert(false);
}

